package com.xrh.xdemo.service.utils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.springframework.core.env.Environment;

import com.xrh.core.generater.bean.DataBaseConfig;
import com.xrh.core.generater.utils.DataBaseUtils;
import com.xrh.core.utils.XAssert;

import cn.hutool.core.bean.BeanDesc;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.PropDesc;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @function bean转表工具类
 * @author 肖荣辉
 * @date 2023年5月17日
*/
public class BeanTableUtils {
	
	/**
	 * @function mysql字段注解
	 * @author 肖荣辉
	 * @date 2023年5月18日
	*/
	@Retention(RetentionPolicy.RUNTIME)
	@Target({ElementType.FIELD , ElementType.TYPE})  
	public  static @interface MysqlColumn{
		
		//字段类型
		String columnType() default "varchar"; 
		
		//字段名称 , 不设置默认取属性名称 , 若为空则取属性名称
		String columnName() default "";
		
		//长度
		int length() default 255;
		
		//-1 , 无索引 , 0 : BTREE索引 , 1 : HASH索引
		int indexType() default -1;
		
		//表备注
		String comment() default "";
	}
	
	/**
	 * @function mysql表注解
	 * @author 肖荣辉
	 * @date 2023年5月18日
	*/
	@Retention(RetentionPolicy.RUNTIME)
	@Target({ElementType.TYPE})  
	public  static @interface MysqlTable{
		
		//表名称没有自动取类名
		String tableName() default ""; 
		
		//表备注
		String comment() default "";
		
	}
	
	/**
	 * @function 特殊字段
	 * @author 肖荣辉
	 * @date 2023年5月17日
	*/
	@AllArgsConstructor
	@NoArgsConstructor
	@Data
	public static class SpecialColumn{
		
		@ApiModelProperty("字段类型")
		private String columnType;
		
		@ApiModelProperty("长度")
		private int length = -1;
		
	}
	
	
	/**
	 * @function 根据ddl创建表
	 * @param ddl 建表语句
	 * @author 肖荣辉
	 * @throws Exception 
	 * @date 2023年5月17日
	*/
	public static int createTable(String ddl) throws Exception {
		
        //创建表
        Environment environment = SpringUtil.getBean(Environment.class);
        
        //数据库信息
        String host = environment.getProperty("datasource.mysql.host");
        String userName = environment.getProperty("datasource.mysql.username");
        String password = environment.getProperty("datasource.mysql.password");
        String dataBaseName = environment.getProperty("datasource.mysql.dbname");
        
        XAssert.isTrue(StrUtil.isNotBlank(host), "数据库datasource.mysql.host不能为空!");
        XAssert.isTrue(StrUtil.isNotBlank(userName), "数据库datasource.mysql.username不能为空!");
        XAssert.isTrue(StrUtil.isNotBlank(password), "数据库datasource.mysql.password不能为空!");
        XAssert.isTrue(StrUtil.isNotBlank(dataBaseName), "数据库datasource.mysql.dbname不能为空!");
        
        String[] arr = host.split(":");
        String ip = arr[0];
        String port = arr[1];
        
        DataBaseConfig dataBaseConfig =   new DataBaseConfig(ip , port , dataBaseName, userName, password);
        
        return   DataBaseUtils.executeUpdateSQL(dataBaseConfig, ddl);
		
	}
	
	
	/**
	 * @function 根据ddl创建数据库
	 * @param ddl 建表语句
	 * @author 肖荣辉
	 * @throws Exception 
	 * @date 2023年5月17日
	*/
	public static void createDatabase() throws Exception {
		
        //创建表
        Environment environment = SpringUtil.getBean(Environment.class);
        
        //数据库信息
        String host = environment.getProperty("datasource.mysql.host");
        String userName = environment.getProperty("datasource.mysql.username");
        String password = environment.getProperty("datasource.mysql.password");
        String dataBaseName = environment.getProperty("datasource.mysql.dbname");
        
        XAssert.isTrue(StrUtil.isNotBlank(host), "数据库datasource.mysql.host不能为空!");
        XAssert.isTrue(StrUtil.isNotBlank(userName), "数据库datasource.mysql.username不能为空!");
        XAssert.isTrue(StrUtil.isNotBlank(password), "数据库datasource.mysql.password不能为空!");
        XAssert.isTrue(StrUtil.isNotBlank(dataBaseName), "数据库datasource.mysql.dbname不能为空!");
        
        String[] arr = host.split(":");
        String ip = arr[0];
        String port = arr[1];
        
        DataBaseConfig dataBaseConfig =   new DataBaseConfig(ip , port , null, userName, password);
        
        String createDbDDL = "CREATE DATABASE IF NOT EXISTS `"+dataBaseName+"` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_0900_ai_ci';";
		
        DataBaseUtils.executeUpdateSQL(dataBaseConfig, createDbDDL);
		
	}
	
	
	/**
	 * @function 根据bean创建表 , 如果table不存在的话
	 * @param clazz
	 * @param tableComment 表注释
	 * @param fileldNameSpecialColumnMap 属性名和字段信息对照map
	 * @param indexFieldNames 索引字段
	 * @author 肖荣辉
	 * @throws Exception 
	 * @date 2023年5月17日
	*/
	public static int createTableIfNotExistByBeanClass(Class<?> clazz) throws Exception {
		
		String ddl = createCreateTableDDL(clazz);
        
        //创建表
        Environment environment = SpringUtil.getBean(Environment.class);
        
        //数据库信息
        String host = environment.getProperty("datasource.mysql.host");
        String userName = environment.getProperty("datasource.mysql.username");
        String password = environment.getProperty("datasource.mysql.password");
        String dataBaseName = environment.getProperty("datasource.mysql.dbname");
        
        XAssert.isTrue(StrUtil.isNotBlank(host), "数据库datasource.mysql.host不能为空!");
        XAssert.isTrue(StrUtil.isNotBlank(userName), "数据库datasource.mysql.username不能为空!");
        XAssert.isTrue(StrUtil.isNotBlank(password), "数据库datasource.mysql.password不能为空!");
        XAssert.isTrue(StrUtil.isNotBlank(dataBaseName), "数据库datasource.mysql.dbname不能为空!");
        
        String[] arr = host.split(":");
        String ip = arr[0];
        String port = arr[1];
        
        DataBaseConfig dataBaseConfig =   new DataBaseConfig(ip , port , dataBaseName, userName, password);
        
        return   DataBaseUtils.executeUpdateSQL(dataBaseConfig, ddl);
		
	}
	
	/**
	 * @function 根据clazz创建表的建表语句(表名就是类名,字段名就是属性名,默认varchar(255))
	 * @param clazz
	 * @param tableComment 表注释
	 * @param fileldNameSpecialColumnMap 属性名和字段信息对照map
	 * @param indexFieldNames 索引字段
	 * @author 肖荣辉
	 * @date 2023年5月17日
	*/
	public static String createCreateTableDDL(Class<?> clazz) {
		
		//获取table注解
		MysqlTable mysqlTable = clazz.getAnnotation(MysqlTable.class);
		
		//以类名为表名
		String tableName = mysqlTable != null && StrUtil.isNotBlank(mysqlTable.tableName()) ? mysqlTable.tableName() : clazz.getSimpleName();
		
		//若没有表备注则取表名称
		String tableComment = mysqlTable != null && StrUtil.isNotBlank(mysqlTable.comment()) ? mysqlTable.comment() : tableName;
		
	     BeanDesc beanDesc = BeanUtil.getBeanDesc(clazz);
	     
         Collection<PropDesc> propDescs = beanDesc.getProps();
         
         String ddl = "CREATE TABLE  IF NOT EXISTS `"+tableName+"`(\n";
         
         ddl += "\t`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',\n";
         ddl += "\t`createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n";
         
         Map<String , String> fieldNameCommentMap = new HashMap<String, String>();
         
         //索引字段和注解对照map
         Map<String , MysqlColumn> fieldNameMysqlColumnMap = new HashMap<String, BeanTableUtils.MysqlColumn>();
         
         for(PropDesc item : propDescs) {
        	 
        	 MysqlColumn mysqlColumn = item.getField().getAnnotation(MysqlColumn.class);
        	 
        	 String comment = mysqlColumn != null ? mysqlColumn.comment() : "";
        	 
        	 //和字段名保持一致好了
        	 String columnName = mysqlColumn != null && StrUtil.isNotBlank(mysqlColumn.columnName()) ? mysqlColumn.columnName() : item.getFieldName();
        	 
        	 fieldNameCommentMap.put(columnName , comment);
        	 
        	 String columnType =  mysqlColumn != null && StrUtil.isNotBlank(mysqlColumn.columnType()) ? mysqlColumn.columnType() : "varchar";
        	 
        	 int length =  mysqlColumn != null ? mysqlColumn.length() : 255;
        	 
        	 length = length <= 0 ? -1 : 255;
        	 
        	 String typeLenTxt = length != -1 ? columnType + "("+length+")" :   columnType;
        	 
        	 ddl += "\t`"+columnName+"` "+typeLenTxt+" DEFAULT NULL COMMENT '"+comment+"',\n";
        	 
        	 if(mysqlColumn != null && mysqlColumn.indexType() != -1) {
        		 fieldNameMysqlColumnMap.put(columnName, mysqlColumn);
        	 }
        	 
         }
         
         
         //主键
         ddl += "\tPRIMARY KEY (`id`) USING BTREE,\n";
         
         //若有索引字段
         for(String indexFieldName : fieldNameMysqlColumnMap.keySet()) {
        	 
        	 String indexType = fieldNameMysqlColumnMap.get(indexFieldName).indexType() == 0 ? "BTREE" : "HASH";
        	 
    		 ddl += "\tKEY `"+indexFieldName+"Index` (`"+indexFieldName+"`) USING "+indexType+" COMMENT '"+fieldNameCommentMap.get(indexFieldName)+"_索引',\n";
    	 }
         
         //去除最后一个逗号
         ddl =  ddl.substring(0 , ddl.lastIndexOf(",")) + "\n";
         
         ddl += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='"+tableComment+"'";
         
         return ddl;
	}

}
